using System.Text;
using LibGit2Sharp;
using Microsoft.VisualBasic.FileIO;
using MultiAgentsShared;

namespace MultiAgentsClient.Tools;

[GptToolSet("File Operation ToolSet", "")]
public class FileOperationToolProvider
{
    [GptFunc("Given file path, check if a file exists", false)]
    public static bool CheckFileExist(
        [GptFuncParam("full filepath to the file")] string filePath)
    {
        return File.Exists(filePath);
    }

    [GptFunc("Given directory path, check if a directory exists", false)]
    public static bool CheckPathExist(
        [GptFuncParam("full filepath to the directory")] string path)
    {
        return Directory.Exists(path) || File.Exists(path);
    }

    [GptFunc("Given file path, load the file contents", true)]
    public static string LoadFile(
        [GptFuncParam("full filepath to the file")] string filePath)
    {
        try
        {
            return File.ReadAllText(filePath);
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    [GptFunc("Given file path, create the file and fill in fileContents.", true)]
    public static string CreateFile(
        [GptFuncParam("full filepath to the file")] string filePath,
        [GptFuncParam("the file content to be fill in the file")] string fileContent
        )
    {
        try
        {
            // Get the directory path from the file path
            string? directoryPath = Path.GetDirectoryName(filePath);

            // Check if the directory path is not null or empty
            if (!string.IsNullOrEmpty(directoryPath))
            {
                // Create the directory if it does not exist
                Directory.CreateDirectory(directoryPath);
            }

            // Write the content to the file, this will automatically create the file
            File.WriteAllText(filePath, fileContent);

            return "File Creation Success";
        }
        catch (Exception ex)
        {
            // Return the exception message if an error occurs
            return ex.Message;
        }
    }

    [GptFunc("Given a directory path, explore the files/folders under that path", false)]
    public static string ExploreDirectory(
        [GptFuncParam("Root directory to start exploring")] string rootDirectory,
        [GptFuncParam("How many depth to explore, -1 is to go through all layers")] int depth = -1,
        int currentLevel = 0)
    {
        List<string> ignoreDirCollection =
        [
            ".vs",
            "packages",
            ".git",
            ".idea",
            "vcpkg_installed",
            "x64"
        ];

        if (Directory.Exists(rootDirectory) == false || depth == 0 || ignoreDirCollection.Contains(Path.GetFileName(rootDirectory)))
        {
            return "";
        }

        StringBuilder sb = new();
        string indent = new(' ', currentLevel * 4); // 4 spaces for each level of depth

        // Add the directory name as a header based on its depth level
        sb.AppendLine($"{indent}- **{new DirectoryInfo(rootDirectory).Name}**");

        // Using LibGit2Sharp to check for ignored files
        Repository? repo = Directory.Exists(rootDirectory + "/.git") ? new(Repository.Discover(rootDirectory)) : null;

        foreach (string dir in Directory.GetDirectories(rootDirectory))
        {
            if ((repo?.Ignore.IsPathIgnored(dir) ?? false) == false)
            {
                sb.AppendLine($"{indent}  - {Path.GetFileName(dir)}◇");
            }
        }

        // Explore files in the current directory
        foreach (string file in Directory.GetFiles(rootDirectory))
        {
            if ((repo?.Ignore.IsPathIgnored(file) ?? false) == false)
            {
                sb.AppendLine($"{indent}  - {Path.GetFileName(file)}");
            }
        }

        // Recursively explore subdirectories if not at the specified depth
        if (depth == -1 || currentLevel < depth - 1)
        {
            foreach (string directory in Directory.GetDirectories(rootDirectory))
            {
                if ((repo?.Ignore.IsPathIgnored(directory) ?? false) == false)
                {
                    sb.Append(ExploreDirectory(directory, depth, currentLevel + 1));
                }
            }
        }

        return sb.ToString();
    }

    [GptFunc("Given folder path, create a folder if it doesn't exist", false)]
    public static bool CreateFolder(
    [GptFuncParam("full path to the folder")] string folderPath)
    {
        try
        {
            if (Directory.Exists(folderPath))
            {
                return false;
            }

            Directory.CreateDirectory(folderPath);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

    [GptFunc("Given file or folder path, delete the file or folder to recycle bin", true)]
    public static bool DeleteFileOrFolderToRecycleBin(
        [GptFuncParam("full path to the file or folder")] string path)
    {
        try
        {
            if (Directory.Exists(path))
            {
                FileSystem.DeleteDirectory(path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
            }
            else if (File.Exists(path))
            {
                FileSystem.DeleteFile(path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
            }
            else
            {
                return false;
            }

            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
}
